package wiModel;

import java.util.Hashtable;
import org.xml.sax.Attributes;
import wiBase.WiException;
import wiBase.WiObject;
import wiBase.baseInterface.OnParseListener;
import wiBase.baseObject.Event;
import wiBase.baseObject.Node;
import wiBase.baseObject.Packet;
import wiBase.baseUtil.Position;

public class WiModelProtocol implements OnParseListener {
    
    private static WiObject _currentObject = null;
    private Hashtable<String, String> _currentFields = new Hashtable<>();
    @SuppressWarnings("unused")
    private String _fileConfig = "";
    private WiModelManager _modelManager = null;
    
    public WiModelProtocol() {
	init();
    }
    
    public WiModelProtocol(String fileConfig) {
	this._fileConfig = fileConfig;
	init();
    }
    
    private void init() {
	_modelManager = WiModelManager.getInstance();
    }
    
    @Override
    public void parseAttributes(String elementName, Attributes atts)
	    throws WiException {

	// WiObject Processing
	WiObject _object_ = null;

	/* Group EventS */
	if (elementName.equals("trace")) {
	    
	} else if (elementName.equals("nodes")) {
	    
	} else if (elementName.equals("packets")) {
	    
	} else if (elementName.equals("events")) {
	    
	} else if (elementName.equals("network")) {
	    String _width = atts.getValue("width");
	    String _length = atts.getValue("length");
	    String _time = atts.getValue("time");
	    
	    _modelManager.setDurationSimulation(Double.parseDouble(_time));
	    _modelManager.setWidth(Double.parseDouble(_width));
	    _modelManager.setLength(Double.parseDouble(_length));
	} else if (elementName.equals("node")) {

	    // parse attributes
	    String _id_ = atts.getValue("id");
	    String _range_ = atts.getValue("range");
	    String _x_ = atts.getValue("x");
	    String _y_ = atts.getValue("y");
	    String _energy_ = atts.getValue("energy");
	    Position _pos_ = new Position(Double.parseDouble(_x_),
		    Double.parseDouble(_y_));

	    // bind object
	    _object_ = new Node(Integer.parseInt(_id_));
	    ((Node) _object_).range = Double.parseDouble(_range_);
	    ((Node) _object_).energy = Double.parseDouble(_energy_);
	    ((Node) _object_).position = _pos_;
	    
	    _currentObject = _object_; // must be end of scope!
	} else if (elementName.equals("packet")) {

	    // parse attributes
	    String _id_ = atts.getValue("id");
	    String _type_ = atts.getValue("type");
	    String _source_id_ = atts.getValue("source-id");
	    String _source_port_ = atts.getValue("source-port");
	    String _dest_id_ = atts.getValue("dest-id");
	    String _dest_port_ = atts.getValue("dest-port");
	    String _size_ = atts.getValue("size");

	    // bind object
	    _object_ = new Packet();
	    ((Packet) _object_).id = _id_;
	    ((Packet) _object_).type = _type_;
	    ((Packet) _object_).sourceId = _source_id_;
	    ((Packet) _object_).sourcePort = _source_port_;
	    ((Packet) _object_).destId = _dest_id_;
	    ((Packet) _object_).destPort = _dest_port_;
	    ((Packet) _object_).size = _size_;
	    
	    _currentObject = _object_; // must be end of scope!
	} else if (elementName.equals("event")) {
	    _object_ = new Event();

	    // parse attributes
	    String _type_ = atts.getValue("type");
	    String _time_ = atts.getValue("time");
	    String _source_port_ = atts.getValue("source-port");
	    String _source_id_ = atts.getValue("source-id");
	    String _remain_energy_ = atts.getValue("remain-energy");
	    String _packet_id_ = atts.getValue("packet-id");
	    String _dest_port_ = atts.getValue("dest-port");
	    String _dest_id_ = atts.getValue("dest-id");
	    String _buffer_length_ = atts.getValue("buffer-length");

	    // parse extra attributes
	    String _reason_ = atts.getValue("reason");
	    String _node_id_ = atts.getValue("node-id");
	    String _curr_x_ = atts.getValue("curr-x");
	    String _curr_y_ = atts.getValue("curr-y");
	    String _curr_z_ = atts.getValue("curr-z");
	    String _dest_x_ = atts.getValue("dest-x");
	    String _dest_y_ = atts.getValue("dest-y");
	    String _dest_z_ = atts.getValue("dest-z");
	    String _speed_ = atts.getValue("speed");

	    // bind object
	    ((Event) _object_).type = _type_;
	    ((Event) _object_).time = _time_;
	    ((Event) _object_).sourcePort = _source_port_;
	    ((Event) _object_).sourceId = _source_id_;
	    ((Event) _object_).remainEnergy = _remain_energy_;
	    ((Event) _object_).packetId = _packet_id_;
	    ((Event) _object_).destPort = _dest_port_;
	    ((Event) _object_).destId = _dest_id_;
	    ((Event) _object_).bufferLength = _buffer_length_;

	    // bind extra values
	    ((Event) _object_).reason = _reason_;
	    ((Event) _object_).nodeId = _node_id_;
	    ((Event) _object_).currX = _curr_x_;
	    ((Event) _object_).currY = _curr_y_;
	    ((Event) _object_).currZ = _curr_z_;
	    ((Event) _object_).destX = _dest_x_;
	    ((Event) _object_).destY = _dest_y_;
	    ((Event) _object_).destZ = _dest_z_;
	    ((Event) _object_).speed = _speed_;
	    
	    _currentObject = _object_; // must be end of scope!
	} else if (elementName.equals("headers")) {
	    
	} else if (elementName.equals("header")) {

	    // parse attributes
	    String _type_ = atts.getValue("type");

	    // bind object
	    _object_ = _currentObject;
	    if (_object_ instanceof Packet) {
		((Packet) _object_).header.type = _type_;
	    } else if (_object_ instanceof Node) {
	    } else if (_object_ instanceof Event) {
	    } else {
		throw new WiException(WiException.TYPE_DEFAULT,
			"Invalid WiObject!");
	    }
	} else if (elementName.equals("field")) {
	    _object_ = _currentObject;
	    // parse attributes
	    String _name_ = atts.getValue("name");

	    // bind object
	    if (_object_ instanceof Packet) {
		_currentFields.put("name", _name_);
	    }
	}
    }
    
    @Override
    public void startElement(String element) {
    }
    
    @Override
    public void endElement(String element) throws WiException {
	WiObject _object_ = null;
	if (element.equals("field")) {
	    if (_currentObject != null) {
		_object_ = _currentObject;
		if (_object_ instanceof Packet) {
		    ((Packet) _object_).header.addField(
			    _currentFields.get("name"),
			    _currentFields.get("value"));
		}
	    }
	} else if (element.equals("node") || element.equals("packet") || element.equals("event")) {
	    _object_ = _currentObject;
	    if (_object_ != null) {
		_modelManager.addWiObjectOrg(_object_);
		_currentObject = null;
	    }
	}
    }
    
    @SuppressWarnings("static-access")
    @Override
    public void startDocument() {
	this._modelManager.setStartTimeParse(System.currentTimeMillis());
	this._modelManager.setParsed(false);
    }
    
    @SuppressWarnings("static-access")
    @Override
    public void finishDocument() {
	this._modelManager.setFinishTimeParse(System.currentTimeMillis());
	this._modelManager.setParsed(true);
    }
    
    @Override
    public void charactor(String content) {
	_currentFields.put("value", content);
    }
}
